home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
pcr
/
pcr4_4.lha
/
UTILITIES
/
copyifdifferent.c
next >
Wrap
C/C++ Source or Header
|
1989-12-20
|
6KB
|
247 lines
/*
* copyifdifferent.c
*
* Demers, December 20, 1989 9:00:32 am PST
*/
#include <stdio.h>
#include <sys/file.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <string.h>
#define BUFBYTES 8192
char *pgmName;
int pflag = 0; /* preserve uid/gid/mtime */
int vflag = 0; /* verbose */
int returnCode = 0;
void
SetReturnCode(n)
int n;
{
if( returnCode < n ) returnCode = n;
}
int
IsDirectory(name)
char *name;
{
struct stat buf;
if( stat(name, &buf) < 0 ) return(0);
return( (buf.st_mode & S_IFDIR) != 0 );
}
char *
MakeDestFileName(srcName, destDirName)
char *srcName;
char *destDirName;
{
char *answer;
char *p;
answer = (char *)(malloc( strlen(srcName) + strlen(destDirName) + 2 ));
(void)strcpy(answer, destDirName);
(void)strcat(answer, "/");
p = strrchr(srcName, '/');
if( p != NULL ) { p += 1; } else { p = srcName; }
(void)strcat(answer, p);
return( answer );
}
int
FirstDifference(p, q, n)
char *p;
char *q;
int n;
{
int i;
for( i = 0; i < n; i++ )
if( *p++ != *q++ ) return(i);
return(-1);
}
void
DoOneFile(srcName, destName)
char *srcName;
char *destName;
{
int srcfd = -1;
int destfd = -1;
char srcbuf[BUFBYTES];
char destbuf[BUFBYTES];
int srccnt, destcnt, i;
struct stat srcstat;
struct stat deststat;
unsigned filepos = 0;
if( vflag ) printf("%s: ", srcName);
srcfd = open(srcName, O_RDONLY, 0);
if( srcfd < 0 ) {
if( vflag ) printf("cannot open.\n");
perror(srcName);
SetReturnCode(1);
goto Out;
}
(void)fstat(srcfd, &srcstat);
destfd = open(destName, O_RDONLY, 0);
if( destfd > 0 ) {
if( vflag ) printf("comparing to %s ... ", destName);
(void)fstat(destfd, &deststat);
if( srcstat.st_size != deststat.st_size ) {
if( vflag ) printf("lengths differ; ");
goto DiffFound;
}
for(;;) {
srccnt = read(srcfd, srcbuf, BUFBYTES);
destcnt = read(destfd, destbuf, BUFBYTES);
if( (srccnt < 0) || (destcnt < 0 ) ) {
if( vflag ) printf("I/O error\n");
perror(((srccnt < 0) ? srcName : destName));
SetReturnCode(1);
goto Out;
}
if( srccnt != destcnt ) {
if( vflag ) printf("premature EOF\n");
fprintf(stderr,"%s: %s/%s premature EOF\n",
pgmName, srcName, destName);
SetReturnCode(1);
goto Out;
}
if( srccnt == 0 ) {
if( vflag ) printf("files identical\n");
goto Out;
}
i = FirstDifference(srcbuf, destbuf, srccnt);
if( i >= 0 ) {
if( vflag ) printf("files differ at %d; ", filepos+i);
goto DiffFound;
}
filepos += srccnt;
}
/*NOTREACHED*/
} else {
if( vflag ) printf("%s nonexistent; ", destName);
goto DiffFound;
}
DiffFound: ;
(void) close(destfd);
if( vflag ) printf("copying ... ");
destfd = open(destName, (O_RDWR|O_CREAT), srcstat.st_mode&07777);
if( destfd < 0 ) {
if( vflag ) printf("cannot create\n");
perror(destName);
SetReturnCode(1);
goto Out;
}
(void)lseek(srcfd, filepos, L_SET);
(void)lseek(destfd, filepos, L_SET);
for(;;) {
srccnt = read(srcfd, srcbuf, BUFBYTES);
if( srccnt == 0 ) break;
if( srccnt > 0 ) {
filepos += srccnt;
destcnt = write(destfd, srcbuf, srccnt);
if( destcnt == srccnt ) continue;
}
if( vflag ) printf("I/O error\n");
fprintf(stderr, "%s: %s, %s I/O error\n",
pgmName, srcName, destName);
SetReturnCode(1);
goto Out;
}
destcnt = ftruncate(destfd, filepos);
if( destcnt < 0 ) {
if( vflag ) printf("truncate error\n");
perror(destName);
SetReturnCode(1);
goto Out;
}
if( pflag ) {
struct timeval tvp[2];
/* change time */
tvp[0].tv_sec = srcstat.st_atime;
tvp[0].tv_usec = 0;
tvp[1].tv_sec = srcstat.st_mtime;
tvp[1].tv_usec = 0;
if( utimes(destName, tvp) < 0 ) {
if( vflag ) printf("can't set times\n");
perror(destName);
SetReturnCode(1);
goto Out;
}
/* change uid/gid */
if( fchown(destfd, srcstat.st_uid, srcstat.st_gid) < 0 ) {
if( vflag ) printf("can't chown\n");
if( getuid() == 0 ) {
perror(destName);
SetReturnCode(1);
goto Out;
} else {
printf("warning: can't chown (not root)\n");
}
}
}
if( vflag ) printf("done\n");
Out:
(void) close(srcfd);
(void) close(destfd);
}
void
Usage(msg)
char *msg;
{
if( msg ) fprintf(stderr, "%s: %s.\n", pgmName, msg);
fprintf(stderr, "Usage: %s [-v] [-p] from to\n", pgmName);
fprintf(stderr, "Usage: %s [-v] [-p] from1 ... fromn todir\n", pgmName);
exit(-1);
}
main(argc, argv)
int argc;
char **argv;
{
int i, isDir;
pgmName = argv[0];
argv += 1; argc -= 1;
for(;;) {
if( argc < 1 ) break;
if( (*argv)[0] != '-' ) break;
switch((*argv)[1]) {
case 'v':
vflag = 1;
break;
case 'p':
pflag = 1;
break;
default:
Usage("bad flag");
}
argv += 1; argc -= 1;
}
if( argc < 2 ) Usage("not enough arguments");
isDir = IsDirectory(argv[argc-1]);
if( (argc > 2) && (!isDir) ) Usage("last arg not directory");
if( isDir ) {
argc -= 1;
for( i = 0; i < argc; i++ ) {
DoOneFile(argv[i], MakeDestFileName(argv[i], argv[argc]));
}
} else {
DoOneFile(argv[0], argv[1]);
}
exit(returnCode);
}